從一個 struct 到一個 抽象資料類型(ADT) 標誌著從「玻璃盒」轉變為「黑箱」的過程,其中「玻璃盒」將所有內部線路暴露無遺,而「黑箱」則將 介面 與 實作分離。這種轉變確保了 封裝:使用者透過函數如 read 或 combine 進行互動,而無需了解收入是如何計算或儲存的。
1. 類別架構
每個類別都定義了一個 獨特的類型識別。即使兩個類別擁有相同的成員,C++ 仍會將它們視為不相容。使用 typedef 和 前向宣告 (例如, class Screen;)讓我們在維持抽象性的同時設計複雜的關係。我們經常使用 合成版本 的建構子,例如 Sales_data() = default;,以保持內建類型的便利性($$total = trans;$$)。
2. 非成員介面函數
像 read 這樣的函數是 非成員類別相關函數。它們屬於介面的一部分,但不是類別本身,通常需要 友誼 才能存取私有資料。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
What is the result of the following code?
struct First { int i; }; struct Second { int i; }; First f; Second s = f;Success: The members are identical.
Error: obj1 and obj2 have different types.
Success: C++ allows structural typing.
Warning: members should be private.
✅ Correct!
In C++, even if members are identical, each class/struct definition creates a unique type identity.❌ Incorrect
Class uniqueness is a fundamental rule; type names matter, not just the contents.QUESTION 2
Which keyword is used to request the compiler to generate a synthesized default constructor?
= auto= synthesized= default= virtual✅ Correct!
= default can appear with the declaration inside the class or the definition outside.❌ Incorrect
The specific syntax introduced in C++11 is = default.QUESTION 3
Why is the
read function typically not a member of the Sales_data class?It requires access to private members.
Member functions cannot return stream references.
IO operations are often conceptually separate from the object's core state logic.
Nonmember functions are faster.
✅ Correct!
Nonmember functions like read and print are part of the interface but kept separate to maintain logical cohesion.❌ Incorrect
While it may need friendship to access private data, the separation is an architectural choice.QUESTION 4
What is the default access level for a
class vs a struct in C++?Both are private by default.
class: private; struct: public.
class: public; struct: private.
Both are public by default.
✅ Correct!
The only technical difference between class and struct is the default access level for members and inheritance.❌ Incorrect
Think of struct as 'data-first' (public) and class as 'logic-first' (private).QUESTION 5
What does a 'forward declaration' like
class Screen; allow you to do?Define the full body of the class later.
Allocate an object of type Screen immediately.
Access the private members of Screen.
Inline all Screen member functions.
✅ Correct!
It introduces the name as an incomplete type, allowing you to define pointers or references to it before the full definition.❌ Incorrect
You cannot instantiate an incomplete type (size is unknown) until it is defined.Architecting the Sales_data Interface
Applying Interface/Implementation Separation
You are tasked with upgrading a legacy struct-based system to a formal ADT. You must implement the standard interface functions while strictly hiding implementation details.
Q
1. Provide the code for Exercise 7.6: Define your own versions of the add, read, and print functions for Sales_data.
Solution:
istream &read(istream &is, Sales_data &item) { double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is; }ostream &print(ostream &os, const Sales_data &item) { os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os; }Sales_data add(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; sum.combine(rhs); return sum; }Q
2. In your Person class (Exercise 7.19), which members should be public and which private? Explain.
Solution:
Data members like
Data members like
string name; and string address; should be private to prevent direct tampering. The public interface should include constructors and 'getter' functions like getName() and getAddress(). This allows the internal storage (e.g., changing string to a custom Name object) to change without breaking user code.Q
3. If a Screen function like
set returns Screen (by value) instead of Screen& (by reference), what happens to the chain myScreen.move(4,0).set('#');?Solution:
The
The
move function returns a temporary copy of myScreen. The subsequent set('#') is called on this temporary copy, not the original myScreen object. Consequently, the original myScreen remains unchanged after the move.